﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2013  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Ext.h".
//-------------------------------------------------------------------

#ifndef _UXS_GLES_STATE_MANAGER_H
#define _UXS_GLES_STATE_MANAGER_H

#include "GLESStatistic.h"
#include "GLESRenderState.h"

namespace UX_STL
{
namespace GLESshell
{

#ifdef UX_SMAN_DISABLE
#	define	SMAN_CHECK_STATE( _check )
#else
#	define	SMAN_CHECK_STATE( _check )	_check
#endif
	


	//
	// State Manager
	//

	class _EXPORT_ GLESStateManager : public GLESBaseObject
	{
		friend class GLESSystem;

	private:
		typedef static_array< GLESTexLayer, UX_MAX_TEXTURE_UNITS >	tex_layers_t;
		
	private:
		GLESStatistic			_cStatistic;

		// Textures //
		tex_layers_t			_aTexLayers;
		uint					_uCurLayer;
		stack< GLESTexLayer, 8>	_sTexStack;

		GLESRenderState			_sStates;

		// GLSL //
		GLuint					_uProgram,
								_uProgramPipeline;	// EXT_separate_shader_objects

		// Buffers //
		GLuint					_uVAO,			// OES_vertex_array_object
								_uIBO,
								_uRBO,
								_uFBO;
		stack< GLuint, 8 >		_sVAOStack;

		// Viewport //
		stack< irect, 8 >		_sViewportStack;

	private:
		bool  _Init();

	public:
		GLESStateManager();
		~GLESStateManager();

		void ActiveTexture(uint stage);
		void BindFramebuffer(GLuint uFBO);
		void BindRenderbuffer(GLuint uRBO);
		void BindMultiTexture(uint stage, gl_texture::type target, GLuint texture);
		void BindProgramPipeline(GLuint pipeline);
		void BindTexture(gl_texture::type target, GLuint texture);
		//void BindBuffer(gl_buffer::type target, GLuint id);
		void BindIndexBuffer(GLuint uIBO);
		void BindVertexArray(GLuint uVAO);
		void BlendState(bool bBlending);
		void BlendEquation(gl_blend_equation::type mode);
		void BlendEquationSeparate(gl_blend_equation::type modeRGB, gl_blend_equation::type modeAlpha);
		void BlendFunc(gl_blend_func::type sfactor, gl_blend_func::type dfactor);
		void BlendFuncSeparate(gl_blend_func::type srcRGB, gl_blend_func::type dstRGB, gl_blend_func::type srcAlpha, gl_blend_func::type dstAlpha);
		void CullFace(gl_face::type mode);
		void CullFaceState(bool mode);
		void ColorMask(bool red, bool green, bool blue, bool alpha);
		void ColorMask(e_color_mask::type eMask);
		void DepthMask(bool mode);
		void DepthTest(bool mode);
		void DepthFunc(gl_compare::type func);
		void StencilTest(bool mode);
		void StencilFunc(gl_compare::type func, GLint ref, GLuint mask);
		void StencilFuncSeparate(gl_face::type face, gl_compare::type func, GLint ref, GLuint mask);
		void StencilMask(GLuint mask);
		void StencilMaskSeparate(gl_face::type face, GLuint mask);
		void StencilOp(gl_stencil_op::type sfail, gl_stencil_op::type dfail, gl_stencil_op::type dppass);
		void StencilOpSeparate(gl_face::type face, gl_stencil_op::type sfail, gl_stencil_op::type dfail, gl_stencil_op::type dppass);
		void FrontFace(gl_front_face::type mode);
		void UseProgram(GLuint uProgram);

		void Viewport(const irect &sArea);			// |_
		void PopViewport();
		void PushViewport()							{ _sViewportStack.Push(); }
		const irect & GetViewport()			const	{ return _sViewportStack.Get(); }
		
		bool PushCurrentTexture();
		bool PopCurrentTexture();

		bool PushVertexArray();
		bool PopVertexArray();

		GLuint	GetIndexBuffer()			const	{ return _uIBO; }
		GLuint	GetFBO()					const	{ return _uFBO; }
		GLuint	GetRBO()					const	{ return _uRBO; }
		GLuint	GetVAO()					const	{ return _uVAO; }
		GLuint	GetProgram()				const	{ return _uProgram; }
		uint	GetCurrentLayer()			const	{ return _uCurLayer; }
		GLuint	GetCurrentTexture()			const	{ return _aTexLayers[_uCurLayer].uID; }
		GLenum	GetCurrentTexTarget()		const	{ return _aTexLayers[_uCurLayer].eTarget; }
		GLuint	GetTexture(uint i)			const	{ return _aTexLayers[i].uID; }
		GLenum	GetTexTarget(uint i)		const	{ return _aTexLayers[i].eTarget; }
		
		e_color_mask::type	GetColorMask()	const;


		// render state //
		GLESRenderState const &	GetRenderState()	const	{ return _sStates; }
		void SetRenderState(const GLESRenderState &rs);
		void SetColorState(const GLESRenderState::TColorBuffer &color);
		void SetDepthState(const GLESRenderState::TDepthState &depth);
		void SetStencilState(const GLESRenderState::TStencilState &stencil);
		void SetCullState(const GLESRenderState::TCullState &cull);
		void SetStates(const GLESRenderState::TStates &states);

		// simple render state //
		void SetColorStateS(const GLESRenderState::TColorBuffer &color);
		void SetStencilStateS(const GLESRenderState::TStencilState::TSide &stencil, bool bEnable);
		void SetPolygonOffset(const vec2 &vOffsets, bool bEnable);


		GLESStatistic * GetStatistic()				{ return &_cStatistic; }

		void Refresh();
		void UnbindTextures();
		void UnbindTexture(uint8 uStage);
		
		void DrawArrays(gl_primitive::type mode, GLint first, GLsizei count);
		void DrawElements(gl_primitive::type mode, GLsizei count, gl_index::type type, const GLvoid * indices);
		void MultiDrawArrays(gl_primitive::type mode, const GLint * first, const GLsizei * count, GLsizei primcount);
		void MultiDrawElements(gl_primitive::type mode, const GLsizei * count, gl_index::type type, const GLvoid ** indices, GLsizei primcount);
	};


/*
=================================================
	активирует текстурный слой
=================================================
*/
	inline void GLESStateManager::ActiveTexture(uint stage)
	{
		SMAN_CHECK_STATE
		(
		if ( stage == _uCurLayer )
			return;
		);
		GL_CALL( glActiveTexture( GL_TEXTURE0 + stage ) );
		_uCurLayer = stage;
	}

/*
=================================================
	устанавливает режим смешивания
=================================================
*/
	inline void GLESStateManager::BlendState(bool bBlending)
	{
		SMAN_CHECK_STATE
		(
		if ( _sStates.sColorBuffer.bBlending == bBlending )
			return;
		)
		GL_CALL( bBlending ? glEnable(  gl_state::BLEND ) :
							   glDisable( gl_state::BLEND ) );
		_sStates.sColorBuffer.bBlending = bBlending;
	}

	inline void GLESStateManager::BlendEquation(gl_blend_equation::type mode)
	{
		SMAN_CHECK_STATE
		(
		if ( _sStates.sColorBuffer.eModeRGB == mode &&
			 _sStates.sColorBuffer.eModeAlpha == mode )
			return;
		)

		GL_CALL( glBlendEquation( mode ) );
		_sStates.sColorBuffer.eModeAlpha = _sStates.sColorBuffer.eModeRGB = mode;
	}

	inline void GLESStateManager::BlendEquationSeparate(gl_blend_equation::type modeRGB, gl_blend_equation::type modeAlpha)
	{
		SMAN_CHECK_STATE
		(
		if ( _sStates.sColorBuffer.eModeRGB == modeRGB &&
			 _sStates.sColorBuffer.eModeAlpha == modeAlpha )
			return;
		)

		GL_CALL( glBlendEquationSeparate( modeRGB, modeAlpha ) );
		_sStates.sColorBuffer.eModeRGB	 = modeRGB;
		_sStates.sColorBuffer.eModeAlpha = modeAlpha;
	}

/*
=================================================
	устанавливает функцию смешивания
=================================================
*/
	inline void GLESStateManager::BlendFunc(gl_blend_func::type sfactor, gl_blend_func::type dfactor)
	{
		SMAN_CHECK_STATE
		(
		if ( _sStates.sColorBuffer.eSrcRGB == sfactor &&
			 _sStates.sColorBuffer.eSrcAlpha == sfactor &&
			 _sStates.sColorBuffer.eDstRGB == dfactor &&
			 _sStates.sColorBuffer.eDstAlpha == dfactor )
			return;
		)

		GL_CALL( glBlendFunc( sfactor, dfactor ) );

		_sStates.sColorBuffer.eSrcRGB = _sStates.sColorBuffer.eSrcAlpha = sfactor;
		_sStates.sColorBuffer.eDstRGB = _sStates.sColorBuffer.eDstAlpha = dfactor;
	}

	inline void GLESStateManager::BlendFuncSeparate(gl_blend_func::type srcRGB, gl_blend_func::type dstRGB,
												 gl_blend_func::type srcAlpha, gl_blend_func::type dstAlpha)
	{
		SMAN_CHECK_STATE
		(
		if ( _sStates.sColorBuffer.eSrcRGB == srcRGB &&
			 _sStates.sColorBuffer.eSrcAlpha == srcAlpha &&
			 _sStates.sColorBuffer.eDstRGB == dstRGB &&
			 _sStates.sColorBuffer.eDstAlpha == dstAlpha )
			return;
		)

		GL_CALL( glBlendFuncSeparate( srcRGB, dstRGB, srcAlpha, dstAlpha ) );

		_sStates.sColorBuffer.eSrcAlpha = srcAlpha;		_sStates.sColorBuffer.eSrcRGB = srcRGB;
		_sStates.sColorBuffer.eDstAlpha = dstAlpha;		_sStates.sColorBuffer.eDstRGB = dstRGB;
	}

/*
=================================================
	устанавливает кадровый буфер
=================================================
*/
	inline void GLESStateManager::BindFramebuffer(GLuint uFBO)
	{
		SMAN_CHECK_STATE
		(
		if ( _uFBO == uFBO ) {
			GLES_COUNTER( ++_cStatistic.uFBORebind; );
			return;
		});
		GLES_COUNTER( ++_cStatistic.uFBOBind; );

		GL_CALL( glBindFramebuffer( GL_FRAMEBUFFER, uFBO ) );
		_uFBO = uFBO;
	}
	
/*
=================================================
	устанавливает рендер буфер
=================================================
*/
	inline void GLESStateManager::BindRenderbuffer(GLuint uRBO)
	{
		SMAN_CHECK_STATE
		(
		if ( _uRBO == uRBO ) {
			GLES_COUNTER( ++_cStatistic.uRBORebind; );
			return;
		});
		GLES_COUNTER( ++_cStatistic.uRBOBind; );

		GL_CALL( glBindRenderbuffer( GL_RENDERBUFFER, uRBO ) );
		_uRBO = uRBO;
	}

/*
=================================================
	устанавливает текстуру
=================================================
*/
	inline void GLESStateManager::BindMultiTexture(uint stage, gl_texture::type target, GLuint texture)
	{
		SMAN_CHECK_STATE
		(
		if ( _aTexLayers[stage].eTarget == target &&
			 _aTexLayers[stage].uID == texture )
		{
			GLES_COUNTER( ++_cStatistic.uTextureRebind; );
			return;
		});
		GLES_COUNTER( ++_cStatistic.uTextureBind; );

		ActiveTexture( stage );
		GL_CALL( glBindTexture( target, texture ) );
		_aTexLayers[stage].eTarget = target;
		_aTexLayers[stage].uID  = texture;
	}

/*
=================================================
	устанавливает текстуру
=================================================
*/
	inline void GLESStateManager::BindTexture(gl_texture::type target, GLuint texture)
	{
		SMAN_CHECK_STATE
		(
		if ( _aTexLayers[_uCurLayer].eTarget == target &&
			 _aTexLayers[_uCurLayer].uID == texture )
		{
			GLES_COUNTER( ++_cStatistic.uTextureRebind; );
			return;
		});
		GLES_COUNTER( ++_cStatistic.uTextureBind; );

		GL_CALL( glBindTexture( target, texture ) );
		_aTexLayers[_uCurLayer].eTarget = target;
		_aTexLayers[_uCurLayer].uID  = texture;
	}

/*
=================================================
	устанавливает шейдерный конвеер
=================================================
*/
	inline void GLESStateManager::BindProgramPipeline(GLuint pipeline)
	{
		SMAN_CHECK_STATE
		(
		if ( _uProgramPipeline == pipeline ) {
			GLES_COUNTER( ++_cStatistic.uPipelineRebind; );
			return;
		});
		GLES_COUNTER( ++_cStatistic.uPipelineBind; );

		GL_CALL( EXT_separate_shader_objects::glBindProgramPipeline( pipeline ) );
		_uProgramPipeline = pipeline;
	}
	
/*
=================================================
	
=================================================
*
	inline void GLESStateManager::BindBuffer(gl_buffer::type target, GLuint id)
	{
		if ( target == gl_buffer::INDEX )
		{
			if ( id != _uIBO )	_uIBO = id;
			else				return;
		}
		GL_CALL( glBindBuffer( target, id ) );
	}
	
/*
=================================================
	
=================================================
*/
	inline void GLESStateManager::BindIndexBuffer(GLuint uIBO)
	{
		SMAN_CHECK_STATE
		(
		if ( _uIBO == uIBO )
			return;
		)

		GL_CALL( glBindBuffer( gl_buffer::INDEX, uIBO ) );
		_uIBO = uIBO;
	}

/*
=================================================
	устанавливает текущий массив вершин
=================================================
*/
	inline void GLESStateManager::BindVertexArray(GLuint uVAO)
	{
		SMAN_CHECK_STATE
		(
		if (  uVAO == _uVAO ) {
			GLES_COUNTER( ++_cStatistic.uVAORebind; );
			return;
		});
		GLES_COUNTER( ++_cStatistic.uVAOBind; );

		GL_CALL( OES_vertex_array_object::glBindVertexArray( uVAO ) );
		_uVAO = uVAO;
		_uIBO = 0;	// reset index buffer
	}

/*
=================================================
	изменяет режин записи в буфер глубины
=================================================
*/
	inline void GLESStateManager::DepthMask(bool mode)
	{
		SMAN_CHECK_STATE
		(
		if ( _sStates.sDepth.bWrite == mode )
			return;
		);

		GL_CALL( glDepthMask( mode ) );
		_sStates.sDepth.bWrite = mode;
	}
	
/*
=================================================
	изменяет режин тест глубины
=================================================
*/
	inline void GLESStateManager::DepthTest(bool mode)
	{
		SMAN_CHECK_STATE
		(
		if ( _sStates.sDepth.bTest == mode )
			return;
		)

		GL_CALL( mode ? glEnable( GL_DEPTH_TEST ) : glDisable( GL_DEPTH_TEST ) );
		_sStates.sDepth.bTest = mode;
	}

/*
=================================================
	изменяет режин записи в буфер глубины
=================================================
*/
	inline void GLESStateManager::DepthFunc(gl_compare::type func)
	{
		SMAN_CHECK_STATE
		(
		if ( _sStates.sDepth.eFunc == func )
			return;
		);

		GL_CALL( glDepthFunc( func ) );
		_sStates.sDepth.eFunc = func;
	}

/*
=================================================
	изменяет режим отсечения полигонов
=================================================
*/
	inline void GLESStateManager::CullFace(gl_face::type mode)
	{
		SMAN_CHECK_STATE
		(
		if ( _sStates.sCull.eCullFace == mode )
			return;
		);

		GL_CALL( glCullFace( mode ) );
		_sStates.sCull.eCullFace = mode;
	}

/*
=================================================
	включает/отключает отсечение полигонов
=================================================
*/
	inline void GLESStateManager::CullFaceState(bool mode)
	{
		SMAN_CHECK_STATE
		(
		if ( _sStates.sCull.bCullFace == mode )
			return;
		)

		GL_CALL( mode ? glEnable( GL_CULL_FACE ) : glDisable( GL_CULL_FACE ) );
		_sStates.sCull.bCullFace = mode;
	}

/*
=================================================
	устанавливает фильтр для цветов
=================================================
*/
	inline void GLESStateManager::ColorMask(bool red, bool green, bool blue, bool alpha)
	{
		const e_color_mask::type	mask = e_color_mask::type( (red << 0) | (green << 1) | (blue << 2) | (alpha << 3) );

		SMAN_CHECK_STATE
		(
		if ( _sStates.sColorBuffer.eMask == mask )
			return;
		)

		GL_CALL( glColorMask( red, green, blue, alpha ) );
		_sStates.sColorBuffer.eMask = mask;
	}

	inline void GLESStateManager::ColorMask(e_color_mask::type eMask)
	{
		SMAN_CHECK_STATE
		(
		if ( _sStates.sColorBuffer.eMask == eMask )
			return;
		)

		GL_CALL( glColorMask( EnumCmp( eMask, e_color_mask::R ),
								EnumCmp( eMask, e_color_mask::G ),
								EnumCmp( eMask, e_color_mask::B ),
								EnumCmp( eMask, e_color_mask::A ) ) );
		_sStates.sColorBuffer.eMask = eMask;
	}

/*
=================================================
	устанавливает направление обхода вершин
=================================================
*/
	inline void GLESStateManager::FrontFace(gl_front_face::type mode)
	{
		SMAN_CHECK_STATE
		(
		if ( _sStates.sCull.eFrontFace == mode )
			return;
		);

		GL_CALL( glFrontFace( mode ) );
		_sStates.sCull.eFrontFace = mode;
	}

/*
=================================================
	устанавливает режим стенсил теста
=================================================
*/
	inline void GLESStateManager::StencilFunc(gl_compare::type func, GLint ref, GLuint mask)
	{
		SMAN_CHECK_STATE
		(
		if ( _sStates.sStencil.aSide[0].eFunc == func &&
			 _sStates.sStencil.aSide[0].uFuncRef == ref &&
			 _sStates.sStencil.aSide[0].uFuncMask == mask &&
			 _sStates.sStencil.aSide[1].eFunc == func &&
			 _sStates.sStencil.aSide[1].uFuncRef == ref &&
			 _sStates.sStencil.aSide[1].uFuncMask == mask )
			return;
		);

		GL_CALL( glStencilFunc( func, ref, mask ) );
		_sStates.sStencil.aSide[0].eFunc		= _sStates.sStencil.aSide[1].eFunc		= func;
		_sStates.sStencil.aSide[0].uFuncRef		= _sStates.sStencil.aSide[1].uFuncRef	= ref;
		_sStates.sStencil.aSide[0].uFuncMask	= _sStates.sStencil.aSide[1].uFuncMask	= mask;
	}

	inline void GLESStateManager::StencilFuncSeparate(gl_face::type face, gl_compare::type func, GLint ref, GLuint mask)
	{
		const uint	i = face == gl_face::FRONT;

		SMAN_CHECK_STATE
		(
		if ( _sStates.sStencil.aSide[i].eFunc == func &&
			 _sStates.sStencil.aSide[i].uFuncRef == ref &&
			 _sStates.sStencil.aSide[i].uFuncMask == mask )
			return;
		);

		GL_CALL( glStencilFuncSeparate( face, func, ref, mask ) );
		_sStates.sStencil.aSide[i].eFunc	 = func;
		_sStates.sStencil.aSide[i].uFuncRef	 = ref;
		_sStates.sStencil.aSide[i].uFuncMask = mask;
	}

/*
=================================================
	устанавливает маску стенсила
=================================================
*/
	inline void GLESStateManager::StencilMask(GLuint mask)
	{
		SMAN_CHECK_STATE
		(
		if ( _sStates.sStencil.aSide[0].uMask == mask &&
			 _sStates.sStencil.aSide[1].uMask == mask )
			return;
		);

		GL_CALL( glStencilMask( mask ) );
		_sStates.sStencil.aSide[0].uMask = _sStates.sStencil.aSide[1].uMask = mask;
	}

	inline void GLESStateManager::StencilMaskSeparate(gl_face::type face, GLuint mask)
	{
		const uint	i = face == gl_face::FRONT;

		SMAN_CHECK_STATE
		(
		if ( _sStates.sStencil.aSide[i].uMask == mask )
			return;
		);

		GL_CALL( glStencilMaskSeparate( face, mask ) );
		_sStates.sStencil.aSide[i].uMask = mask;
	}
	
/*
=================================================
	изменяет режим тест стенсила
=================================================
*/
	inline void GLESStateManager::StencilTest(bool mode)
	{
		SMAN_CHECK_STATE
		(
		if ( _sStates.sStencil.bTest == mode )
			return;
		)

		GL_CALL( mode ? glEnable( GL_STENCIL_TEST ) : glDisable( GL_STENCIL_TEST ) );
		_sStates.sStencil.bTest = mode;
	}
	
/*
=================================================
	устанавливает операции стенсила
=================================================
*/
	inline void GLESStateManager::StencilOp(gl_stencil_op::type sfail, gl_stencil_op::type dfail, gl_stencil_op::type dppass)
	{
		SMAN_CHECK_STATE
		(
		if ( _sStates.sStencil.aSide[0].eSFail == sfail &&
			 _sStates.sStencil.aSide[0].eDFail == dfail &&
			 _sStates.sStencil.aSide[0].eDPPass == dppass &&
			 _sStates.sStencil.aSide[1].eSFail == sfail &&
			 _sStates.sStencil.aSide[1].eDFail == dfail &&
			 _sStates.sStencil.aSide[1].eDPPass == dppass )
			return;
		);

		GL_CALL( glStencilOp( sfail, dfail, dppass ) );
		_sStates.sStencil.aSide[0].eSFail	= _sStates.sStencil.aSide[1].eSFail	 = sfail;
		_sStates.sStencil.aSide[0].eDFail	= _sStates.sStencil.aSide[1].eDFail	 = dfail;
		_sStates.sStencil.aSide[0].eDPPass	= _sStates.sStencil.aSide[1].eDPPass = dppass;
	}

	inline void GLESStateManager::StencilOpSeparate(gl_face::type face, gl_stencil_op::type sfail, gl_stencil_op::type dfail, gl_stencil_op::type dppass)
	{
		const uint	i = face == gl_face::FRONT;

		SMAN_CHECK_STATE
		(
		if ( _sStates.sStencil.aSide[i].eSFail == sfail &&
			 _sStates.sStencil.aSide[i].eDFail == dfail &&
			 _sStates.sStencil.aSide[i].eDPPass == dppass )
			return;
		);

		GL_CALL( glStencilOpSeparate( face, sfail, dfail, dppass ) );
		_sStates.sStencil.aSide[i].eSFail	= sfail;
		_sStates.sStencil.aSide[i].eDFail	= dfail;
		_sStates.sStencil.aSide[i].eDPPass	= dppass;
	}

/*
=================================================
	устанавливает программу
=================================================
*/
	inline void GLESStateManager::UseProgram(GLuint uProgram)
	{
		SMAN_CHECK_STATE
		(
		if ( uProgram == _uProgram ) {
			GLES_COUNTER( ++_cStatistic.uProgramRebind; );
			return;
		});
		GLES_COUNTER( ++_cStatistic.uProgramBind; );

		GL_CALL( glUseProgram( uProgram ) );
		_uProgram = uProgram;
	}

/*
=================================================
	установить размеры поля вывода
=================================================
*/
	inline void GLESStateManager::Viewport(const irect &sArea)
	{
		ASSERT( sArea.w-sArea.x != 0 && sArea.h-sArea.y != 0 );

		_sViewportStack.Get() = sArea;
		GL_CALL( glViewport( sArea.x, sArea.y, sArea.w-sArea.x, sArea.h-sArea.y ) );
	}
	
/*
=================================================
	вернуть предыдущий размер поля ввода
=================================================
*/
	inline void GLESStateManager::PopViewport()
	{
		_sViewportStack.Pop();
		const irect	&s_area = _sViewportStack.Get();

		GL_CALL( glViewport( s_area.x, s_area.y, s_area.w-s_area.x, s_area.h-s_area.y ) );
	}
	
/*
=================================================
	сохранить текстуру
=================================================
*/
	inline bool GLESStateManager::PushCurrentTexture()
	{
		return _sTexStack.Push( GLESTexLayer( _aTexLayers[_uCurLayer].eTarget, _aTexLayers[_uCurLayer].uID ) );
	}
	
/*
=================================================
	установить предыдущую текстуру
=================================================
*/
	inline bool GLESStateManager::PopCurrentTexture()
	{
		if ( _sTexStack.Pop() ) {
			BindTexture( _sTexStack.Get().eTarget, _sTexStack.Get().uID );
			return true;
		}
		return false;
	}
	
/*
=================================================
	сохранить массив вершин
=================================================
*/
	inline bool GLESStateManager::PushVertexArray()
	{
		return _sVAOStack.Push( _uVAO );
	}
	
/*
=================================================
	установить предыдущий массив вершин
=================================================
*/
	inline bool GLESStateManager::PopVertexArray()
	{
		if ( _sVAOStack.Pop() ) {
			BindVertexArray( _sVAOStack.Get() );
			return true;
		}
		return false;
	}
	
/*
=================================================
	отключает текстуру
=================================================
*/
	inline void GLESStateManager::UnbindTexture(uint8 uStage)
	{
		BindMultiTexture( uStage, gl_texture::TEXTURE_2D, 0 );
	}

/*
=================================================
	рисует примитивы, если включена
	тесселяция, то изменяет тип примитивов
=================================================
*/
	inline void GLESStateManager::DrawArrays(gl_primitive::type mode, GLint first, GLsizei count)
	{
		GLES_COUNTER(
			_cStatistic.uPrimitiveCounter += count;
			_cStatistic.uDrawCalls++;
		);
		GL_CALL( glDrawArrays( mode, first, count ) );
	}


	inline void GLESStateManager::DrawElements(gl_primitive::type mode, GLsizei count, gl_index::type type, const GLvoid * indices)
	{
		GLES_COUNTER(
			_cStatistic.uPrimitiveCounter += count;
			_cStatistic.uDrawCalls++;
		);
		GL_CALL( glDrawElements( mode, count, type, indices ) );
	}


	inline void GLESStateManager::MultiDrawArrays(gl_primitive::type mode, const GLint * first, const GLsizei * count, GLsizei primcount)
	{
		GLES_COUNTER(
			_cStatistic.uDrawCalls++;
			for (GLsizei i = 0; i < primcount; ++i)
				_cStatistic.uPrimitiveCounter += count[i];
		);
		GL_CALL( EXT_multi_draw_arrays::glMultiDrawArrays( mode, first, count, primcount ) );
	}


	inline void GLESStateManager::MultiDrawElements(gl_primitive::type mode, const GLsizei * count, gl_index::type type, const GLvoid ** indices, GLsizei primcount)
	{
		GLES_COUNTER(
			_cStatistic.uDrawCalls++;
			for (GLsizei i = 0; i < primcount; ++i)
				_cStatistic.uPrimitiveCounter += count[i];
		);
		GL_CALL( EXT_multi_draw_arrays::glMultiDrawElements( mode, count, type, indices, primcount ) );
	}

//-------------------------------------------------------------------

}	// GLESshell
}	// UX_STL

#endif	// _UXS_GL_STATE_MANAGER_H